﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Project_CFT2.RFID
{
    public struct RFIDDataRx
    {
        public long id;
        public int type;
    }


    public enum IdTx { Read, ReadLine, Program };

    //RFID—˜‚¾[§Œä—pƒNƒ‰ƒX
    public class RFIDComm
    {
        //RFIDƒŠ[ƒ_[‚É‘—M‚·‚é\‘¢‘Ì
        private struct RFIDCommandTx	//Max Length = 41
        {
            public byte start;
            public byte length;
            public byte command1;
            public byte command2;
            public byte[] data;
            public byte bcc;
        }
        //RFIDƒŠ[ƒ_[‚©‚çŽóM‚·‚é\‘¢‘Ì
        private struct RFIDCommandRx
        {
            public byte start;
            public byte length;
            public byte status;
            public byte[] data;
            public byte bcc;

        }

        //RFIDƒŠ[ƒ_[‚Æ‚Ì’ÊMŒ‹‰Ê‚ðŽ¦‚·’è”
        public const int RX_ID_ERROR_READ = -2;
        public const int RX_ID_OTHER_READ = -1;
        public const int RX_ID_NO_READ = 0;
        //ƒ^ƒO‚ÌŽí—Þ‚ðŽ¦‚·’è”
        public const int RX_TYPE_RO = 0x00;
        public const int RX_TYPE_RW = 0x01;
        public const int RX_TYPE_MPT = 0x02;
        public const int RX_TYPE_OTHER = 0x03;

        //’ÊM—p‚ÌƒXƒ^[ƒgƒoƒCƒg
        const byte SOH = 0x01;

        //RFID‚Ö‚Ì–½—ß‚ð•\‚·’è”
        const byte READ_SINGLE = 0x08;
        const byte READ_NORMAL = 0x09;
        const byte READ_LINE = 0x0A;
        const byte PROGRAM_SINGLE = 0xE8;	//1110 1000[Power Burst1&2 with Data, Single, No FBCC, CommandField2]
        const byte PROGRAM_SINGLE2 = 0x06;	// 0000 0110Wireless Synchronization, Calcurate DBCC

        //ƒVƒŠƒAƒ‹ƒ|[ƒg’ÊM—pƒNƒ‰ƒX‚ÌéŒ¾
        Rs232c comm;

        //ƒRƒ“ƒXƒgƒ‰ƒNƒ^
        public RFIDComm(string port, int baudRate)
        {
            comm = new Rs232c(port, baudRate);
        }

        //ƒVƒŠƒAƒ‹’ÊM—pƒ|[ƒg”Ô†‚ðÝ’èCŽæ“¾‚·‚é
        public string Port
        {
            set { comm.Port = value; }
            get { return comm.Port; }
        }

        //ƒVƒŠƒAƒ‹’ÊMƒ|[ƒg‚ðŠJ‚­
        public bool Open()
        {
            bool flag = comm.Open();
            return flag;
        }

        //ƒVƒŠƒAƒ‹’ÊMƒ|[ƒg‚ð•Â‚¶‚é
        public void Close()
        {
            comm.Close();
            return;
        }

        //ƒVƒŠƒAƒ‹’ÊMƒ|[ƒg‚ªŠJ‚¢‚Ä‚¢‚ê‚ÎtrueC•Â‚¶‚Ä‚¢‚ê‚Îfalse
        public bool IsOpen
        {
            get { return this.comm.IsOpen; }
        }


        //RFIDƒŠ[ƒ_‚ÉƒƒbƒZ[ƒW‚ð‘—M
        public bool SendMessage(IdTx id, ref byte[] txBytes)
        {
            byte[] data = new byte[1];
            return SendMessage(id, data, ref txBytes);
        }

        //ƒVƒŠƒAƒ‹ƒ|[ƒg‚ð’Ê‚¶‚ÄCRFIDƒŠ[ƒ_‚ÉƒƒbƒZ[ƒW‚ð‘—M
        public bool SendMessage(IdTx id, byte[] data, ref byte[] txBytes)
        {

            RFIDCommandTx commandTx;

            commandTx = new RFIDCommandTx();
            commandTx.start = SOH;

            switch (id)
            {
                case IdTx.Read:
                    commandTx.length = 2;
                    commandTx.command1 = READ_SINGLE;
                    commandTx.data = new byte[1];
                    commandTx.data[0] = 50;
                    commandTx.bcc = (byte)(commandTx.length ^ commandTx.command1 ^ commandTx.data[0]);

                    break;
                case IdTx.ReadLine:
                    commandTx.length = 2;
                    commandTx.command1 = READ_LINE;
                    commandTx.data = new byte[1];
                    commandTx.data[0] = 50;
                    commandTx.bcc = (byte)(commandTx.length ^ commandTx.command1 ^ commandTx.data[0]);

                    break;
                case IdTx.Program:
                    commandTx.length = 17;
                    commandTx.command1 = PROGRAM_SINGLE;
                    commandTx.command2 = PROGRAM_SINGLE2;
                    commandTx.data = new byte[15];
                    commandTx.data[0] = 50;		//Power Burst1
                    commandTx.data[1] = 15;		//Power Burst2
                    commandTx.data[2] = 12;		//Data Fields Follow
                    commandTx.data[3] = 0xBB;	//Write Keyword
                    commandTx.data[4] = 0xEB;	//Write Password
                    for (int i = 0; i < 8; i++)		//Write Data(LSByte First)
                    {
                        commandTx.data[i + 5] = data[i];
                    }

                    commandTx.data[13] = 0x00;	//Write Frame
                    commandTx.data[14] = 0x03;  //Write Frame

                    commandTx.bcc = (byte)(commandTx.length ^ commandTx.command1 ^ commandTx.command2);
                    for (int i = 0; i < 15; i++)
                    {
                        commandTx.bcc = (byte)(commandTx.bcc ^ commandTx.data[i]);
                    }
                    break;
                default:
                    return false;
            }

            //\‘¢‘Ì‚ðƒoƒCƒg—ñ‚É•ÏŠ·
            txBytes = ConvertToBytes(commandTx);
            //ƒVƒŠƒAƒ‹ƒ|[ƒg‚ÉƒoƒCƒg—ñ‚ðo—Í
            comm.WriteBytes(txBytes);

            return true;
        }

        //ƒVƒŠƒAƒ‹ƒ|[ƒg‚ð’Ê‚¶‚ÄCRFIDƒŠ[ƒ_‚©‚çƒƒbƒZ[ƒW‚ðŽóM‚µCID‚ðŽæ“¾
        public bool ReceiveMessage(ref byte[] rxBytes, ref RFIDDataRx dataRx)
        {
            if (!comm.IsOpen)
                return false;

            bool flag = comm.ReadBytes(ref rxBytes);

            if (!flag)
                return false;

            //“ü—Íƒf[ƒ^‚Ì”»•Ê
            RFIDCommandRx commandRx;

            if (rxBytes[0] != RFIDComm.SOH)
            {
                dataRx.id = RFIDComm.RX_ID_ERROR_READ;
                return false;
            }

            if (rxBytes[1] == 1)//No Read
            {
                if (rxBytes.Length < 4)
                {
                    dataRx.id = RFIDComm.RX_ID_ERROR_READ;
                    return false;
                }

                commandRx.start = rxBytes[0];
                commandRx.length = rxBytes[1];
                commandRx.status = rxBytes[2];
                commandRx.bcc = rxBytes[3];
                dataRx.id = RFIDComm.RX_ID_NO_READ;
                return true;
            }
            else if (rxBytes[1] == 9)
            {
                if (rxBytes.Length < 11)
                {
                    dataRx.id = RFIDComm.RX_ID_ERROR_READ;
                    return false;
                }
                commandRx.start = rxBytes[0];
                commandRx.length = rxBytes[1];
                commandRx.status = rxBytes[2];
                commandRx.data = new byte[8];
                for (int i = 0; i < 8; i++)
                {
                    commandRx.data[i] = rxBytes[i + 3];
                }
                commandRx.bcc = rxBytes[11];
                dataRx.type = commandRx.status & 0x03;				//‰º“ñƒrƒbƒg‚ðŠi”[
                dataRx.id = BitConverter.ToInt64(commandRx.data, 0);
                return true;
            }
            else
            {
                if (rxBytes.Length < 3)
                {
                    dataRx.id = RFIDComm.RX_ID_ERROR_READ;
                    return false;
                }

                dataRx.type = rxBytes[2] & 0x03;
                dataRx.id = RFIDComm.RX_ID_OTHER_READ;
                return true;
            }
        }


        //RFIDCommandTxŒ^\‘¢‘Ì‚ðƒoƒCƒg—ñ‚É•ÏŠ·
        private byte[] ConvertToBytes(RFIDCommandTx tx)
        {
            byte[] txBytes = new byte[3 + tx.length];
            txBytes[0] = tx.start;
            txBytes[1] = tx.length;
            txBytes[2] = tx.command1;

            if (tx.command2 != 0)
            {
                txBytes[3] = tx.command2;
                for (int i = 0; i < tx.length - 2; i++)
                {
                    txBytes[i + 4] = tx.data[i];
                }
            }

            else
            {
                for (int i = 0; i < tx.length - 1; i++)
                {
                    txBytes[i + 3] = tx.data[i];
                }

            }
            txBytes[2 + tx.length] = tx.bcc;
            return txBytes;
        }

    }
}
